package com.shao.intelligentsnake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

/**
 * @author shaohuailin
 * @date 2024/4/20
 */
public class GameScene extends JPanel implements KeyListener {

    // 线程安全的参数对象
    private GameParams params = new GameParams();

    /**
     * 获取参数对象
     *
     * @return
     */
    public GameParams getParams() {
        return params;
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        // 获取参数
        int size = params.getSize();
        int unit = params.getUnit();
        int[] snakePosition = params.getSnakePosition();
        int foodPosition = params.getFoodPosition();
        boolean gameOver = params.isGameOver();
        // 绘制边界
        g.setColor(Color.BLACK);
        g.drawRect(0, 0, size*unit, size*unit);
        // 绘制蛇
        for (int position : snakePosition) {
            int x = position >> 8 & 0xFF;
            int y = position & 0xFF;
            boolean isTail = snakePosition[snakePosition.length - 1] == position;
            g.setColor(snakePosition[0] == position ? Color.BLUE : isTail ? new Color(0, 200, 0) : Color.GREEN);
            g.fillRect(x*unit, y*unit, unit, unit);
            g.setColor(Color.BLACK);
            g.drawRect(x*unit, y*unit, unit, unit);
        }
        // 绘制食物
        g.setColor(Color.RED);
        int xFood = foodPosition >> 8 & 0xFF;
        int yFood = foodPosition & 0xFF;
        g.fillRect(xFood*unit, yFood*unit, unit, unit);
        // 游戏结束
        if (gameOver) {
            g.setColor(Color.RED);
            g.drawString("Game Over", 0, size*unit+unit);
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
        // not
    }

    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        // 游戏结束了，禁止移动
        if (params.isGameOver()) {
            return;
        }
        if (keyCode == KeyEvent.VK_UP) {
            // 上移
            doMoveDirection(0);
        }
        else if (keyCode == KeyEvent.VK_DOWN) {
            // 下移
            doMoveDirection(1);
        }
        else if (keyCode == KeyEvent.VK_LEFT) {
            // 左移
            doMoveDirection(2);
        }
        else if (keyCode == KeyEvent.VK_RIGHT) {
            // 右移
            doMoveDirection(3);
        }
        else if (keyCode == KeyEvent.VK_SPACE) {
            params.setOpenAutomatic(!params.isOpenAutomatic());
            if (params.isOpenAutomatic()) {
                System.out.println("开启自动模式");
                new Automatic(this).open();
            } else {
                System.out.println("关闭自动模式");
            }
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // not
    }

    /**
     * 向指定方向移动
     *
     * @param direction 0:上 1:下 2:左 3:右
     */
    private void doMoveDirection(int direction) {
        int[] snakePosition = params.getSnakePosition();
        int size = params.getSize();
        // 头部坐标
        int xSnake = snakePosition[0] >> 8 & 0xFF;
        int ySnake = snakePosition[0] & 0xFF;
        boolean move = false;
        if (direction == 0 && ySnake > 0) {
            // 上移
            ySnake = ySnake - 1;
            move = true;
        }
        else if (direction == 1 && ySnake + 1 < size) {
            // 下移
            ySnake = ySnake + 1;
            move = true;
        }
        else if (direction == 2 && xSnake > 0) {
            // 左移动
            xSnake = xSnake - 1;
            move = true;
        }
        else if (direction == 3 && xSnake + 1 < size) {
            // 右移动
            xSnake = xSnake + 1;
            move = true;
        }
        int position = xSnake << 8 | ySnake;
        if (move) {
            doMovePosition(position);
        }
    }

    /**
     * 移动到具体位置
     *
     * @param position 位置
     */
    public void doMovePosition(int position) {
        int[] snakePosition = params.getSnakePosition();
        int foodPosition = params.getFoodPosition();
        // 判断是否撞到自己，撞到了就标记游戏结束
        for (int p : snakePosition) {
            if (position == p) {
                System.out.println("撞到自己了，位置：" + position);
                params.setGameOver(true);
                break;
            }
        }
        int snakeLen = snakePosition.length;
        // 若吃到食物，长度增加
        if (position == foodPosition) {
            snakeLen++;
            // 食物重新刷新
            int food = refreshFood();
            if (food == -1) {
                System.out.println("无法播放食物了");
            } else {
                params.setFoodPosition(food);
            }
        }
        // 更新蛇的位置信息
        int[] newSnakePosition = new int[snakeLen];
        newSnakePosition[0] = position;
        System.arraycopy(snakePosition, 0, newSnakePosition, 1, snakeLen - 1);
        params.setSnakePosition(newSnakePosition);
        // 状态表先重置
        params.setStateTable(new int[0xFFFF]);
        // 更新食物位置状态表
        params.setStateTable(foodPosition, GameParams.STATE_FOOD);
        // 更新蛇的位置状态表
        for (int pos : newSnakePosition) {
            params.setStateTable(pos, GameParams.STATE_SNAKE);
        }
        // 重新绘制
        this.repaint();
    }

    /**
     * 刷新食物位置
     * @return 新的食物位置，-1表示无位置
     */
    private int refreshFood() {
        int size = params.getSize();
        int[] stateTable = params.getStateTable();
        // 定义存储数组
        int[] arr = new int[size*size];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = -1;
        }
        int endId = -1;
        for (int x = 0; x < size; x++) {
            for (int y = 0; y < size; y++) {
                int position = x << 8 | y;
                if (stateTable[position] == GameParams.STATE_EMPTY) {
                    arr[++endId] = position;
                }
            }
        }
        if (endId == -1) {
            return -1;
        }
        else if (endId < 3) {
            return arr[0];
        }
        else {
            int randomId = new Random().nextInt(endId);
            return arr[randomId];
        }
    }
}
